#include "common.h"

class UdpServer 
{
  public:
    // 构造函数，创建一个服务器对象时需要显示传入一个端口号给服务器
    UdpServer(const int port)
      :_port(port)
      ,_sockfd(-1)
    {}

    // 析构函数，当服务器对象销毁时关闭打开的文件描述符
    ~UdpServer()
    {
      if(_sockfd >= 0)
      {
        close(_sockfd);
      }
    }

    // 初始化服务器
    void InitServer()
    {
      // 1、创建socket文件描述符
      if((_sockfd=socket(AF_INET, SOCK_DGRAM, 0)) == -1)
      {
        cerr<<"socket error"<<endl;
        return;
      }
      cout<<"socket sucess"<<endl;

      // 2、将服务器自己的协议地址和刚刚创建的socket文件描述符绑定起来
      struct sockaddr_in local;
      local.sin_family = AF_INET;
      local.sin_port = htons(_port); 
      local.sin_addr.s_addr = htonl(INADDR_ANY);
      if(bind(_sockfd, (struct sockaddr*)&local, sizeof(struct sockaddr)) == -1)
      {
        cerr <<"bind error"<<endl;
        return;
      }
      cout<<"bind sucess"<<endl;
    }

    // 启动服务器
    void Loop()
    {
#define SIZE 128
      // buffer用于接收客户端传来的数据
      char buffer[SIZE];
      // peer用于接收客户端的协议地址信息
      struct sockaddr_in peer;
      memset(&peer, 0, sizeof(struct sockaddr))
      // len用来接收客户端协议地址结构的大小
      socklen_t len = sizeof(struct sockaddr);

      while(true)
      {
        // 1、通过recvfrom函数不断接收客户端传来的数据和信息
        ssize_t size = recvfrom(_sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
        // 2、解析客户端的数据和信息
        if(size >= 0)
        {
          buffer[size] = '\0';
          int port = ntohs(peer.sin_port);
          string ip = inet_ntoa(peer.sin_addr);
          cout<<'['<<ip<<' '<<port<<"]#"<<buffer<<endl;
        }
        else
        {
          cerr<<"recvfrom error"<<endl;
        }
      }
    }

  private:
    int _port;  // 服务器进程的端口号
    int _sockfd;// 服务器进程的socket打开文件描述符
};
